package org.snail.proxy.server.netty.http;

import com.google.protobuf.ByteString;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snail.proxy.proto.CreateClientRequest;
import org.snail.proxy.proto.HttpMessage;
import org.snail.proxy.proto.HttpMethod;
import org.snail.proxy.proto.MessageId;
import org.snail.proxy.proto.Packet;
import org.snail.proxy.proto.ProxyMessage;
import org.snail.proxy.server.netty.ProxyClientHandler;

import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@ChannelHandler.Sharable
public class HttpProxyHandler extends SimpleChannelInboundHandler<HttpRequest> {
    private static final Logger log = LoggerFactory.getLogger(HttpProxyHandler.class);

    private final Channel proxyClientChannel;
    private final ProxyClientHandler proxyClientHandler;

    public HttpProxyHandler(Channel proxyClientChannel, ProxyClientHandler proxyClientHandler) {
        this.proxyClientChannel = proxyClientChannel;
        this.proxyClientHandler = proxyClientHandler;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpRequest req) {
        String id = UUID.randomUUID().toString();
        proxyClientHandler.addProxyChannel(id, ctx.channel());
        CreateClientRequest request = CreateClientRequest.newBuilder().setId(id).build();
        proxyClientChannel.writeAndFlush(new Packet((byte) 0, MessageId.CREATE_CLIENT_REQUEST_VALUE, request.toByteArray()));

        HttpMessage httpMessage = HttpMessage.newBuilder()
                .setMethod(HttpMethod.valueOf(req.method().name().toUpperCase()))
                .putAllHeaders(req.headers().entries().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))
                .setUri(req.uri())
                .setBody(req instanceof FullHttpRequest ? ByteString.copyFrom(((FullHttpRequest) req).content().array()) : ByteString.EMPTY)
                .build();
        ProxyMessage proxyMessage = ProxyMessage.newBuilder().setId(id).setData(httpMessage.toByteString()).build();
        proxyClientChannel.writeAndFlush(new Packet((byte) 0, MessageId.PROXY_MESSAGE_VALUE, proxyMessage.toByteArray()));
        log.info("Transform http message {}[{}, {}].", id, req.uri(), httpMessage.getBody().size());
    }
}
